package com.mrd.gtimp.business.service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mrd.framework.config.web.json.Result;
import com.mrd.gtimp.business.entity.PayResponseResolveLog;
import com.mrd.gtimp.business.repository.PayResponseResolveLogDao;
import com.mrd.gtimp.v2.fund.FundIETypeEnum;
import com.mrd.gtimp.v2.fund.FundStateEnum;
import com.mrd.payClient.utils.ProperUtils;
import com.mrd.util.PayProperties;
import com.mrd.util.StringUtils;
import com.mrd.util.endecrypt.MD5Util;

import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 处理支付平台相关业务
 * Created by dengdc on 2017/7/3.
 */
@Service
public class PaymentPlatformBiz extends CommonPaymentBiz{

    private static Logger logger = Logger.getLogger(PaymentPlatformBiz.class);

    @Resource
    private PayResponseResolveLogDao payResponseResolveLogDao;
    @Resource
    private JdbcTemplate jdbcTemplate;
    @Resource
    private PayProperties payProperties;

    /**
     * 支付平台返回的支付状态
     */
    public enum platformPaymentStatus{
        /**
         * 成功
         */
        SUCCESS,
        /**
         * 失败
         */
        FAIL
    }

    /**
     * 处理支付平台参入的关于支付结果的json字符串
     * @param jsonStr json格式的支付结果字符串
     * 示例：
     * {
     *   orderId:支付平台生成的ID，                <br/>
     *   time_end:支付平台发出此通知的时间，       <br/>
     *   transaction_id:微信支付订单号，           <br/>
     *   outTradeNo：交易订单号，                  <br/>
     *   total_fee：金额（精确到分，人民币），      <br/>
     *   status:交易状态（SUCCESS 成功，FAIL 失败）<br/>
     * }
     * @return 处理结果
     */
    @Transactional
    public Result resolveJsonStrFromPaymentPlatform(String jsonStr){
        if(StringUtils.isEmpty(jsonStr)){
            logger.info("错误的参数：" + jsonStr);
            System.out.println("错误的参数：" + jsonStr);
            return Result.newFailInstance("错误的参数");
        }
        logger.info("收到支付平台通知：" + jsonStr);
        Result resolveResult = null;
        //创建回执解析记录，填入回执来源为支付平台；填入接收到的回执json字符串
        PayResponseResolveLog payResponseResolveLog = new PayResponseResolveLog(PayResponseResolveLog.ResponseFromEnum.PayPlatform, jsonStr);

        //对回执进行解析
        PaymentPlatformResult result = null;
        try {
            result = new PaymentPlatformResult(jsonStr);
        } catch (Exception e) {
            //异常信息保存到解析记录中，并在解析记录中标记“出现了异常”。
            payResponseResolveLog.setCatchException(true);
            payResponseResolveLog.setExceptionMsg("解析支付平台回执时出现异常：" + e.getMessage());
            payResponseResolveLogDao.save(payResponseResolveLog); //保存

            //保存日志记录
            logger.error("解析支付平台回执数据["+jsonStr+"]时出现异常：" + e.getMessage());
            return Result.newFailInstance("解析支付平台回执数据时出现异常");
        }
        resolve(payResponseResolveLog, result);

        return resolveResult;
    }

    /**
     * 处理页面通知的请求
     * @param request
     * @return
     */
    @Transactional
    public Result resolveRequestFromPaymentPlatform(HttpServletRequest request){
        logger.info("收到支付平台页面通知，开始解析");
        //对回执进行解析
        PaymentPlatformResult result = null;
        PayResponseResolveLog payResponseResolveLog = new PayResponseResolveLog();
        payResponseResolveLog.setFrom(PayResponseResolveLog.ResponseFromEnum.PayPlatform.toString());
        Result pageResult = null;
        try {
            result = new PaymentPlatformResult(request);
            payResponseResolveLog.setData(result.toString());
            String yxtSign = MD5Util.string2MD5(payProperties.getAlipay() + result.getOutTradeNo());
            if(!result.getSign().equals(yxtSign)){
                payResponseResolveLog.setStatus(PayResponseResolveLog.ResolveStatusEnum.Abandon.toString());
                payResponseResolveLog.setData(payResponseResolveLog.getData() + "，签名错误");
                logger.error("解析支付平台页面通知时发现签名错误");
                pageResult = Result.newFailInstance("");
            }
        } catch (Exception e) {
            //异常信息保存到解析记录中，并在解析记录中标记“出现了异常”。
            payResponseResolveLog.setCatchException(true);
            payResponseResolveLog.setExceptionMsg("解析支付平台页面通知时出现异常：" + e.getMessage());
            payResponseResolveLogDao.save(payResponseResolveLog); //保存

            //保存日志记录
            logger.error("解析支付平台页面通知时出现异常：" + e.getMessage());
        }

        String resolveFlag = resolve(payResponseResolveLog, result);
        if("SUCCESS".equals(resolveFlag)){
            pageResult = Result.newSuccessInstance("预付款到账");
        }else{
            pageResult = Result.newSuccessInstance("支付失败");
        }
        return pageResult;
    }

    /**
     *
     * @param payResponseResolveLog
     * @param resolveResult
     * @return
     */
    @Transactional
    public String resolve(PayResponseResolveLog payResponseResolveLog, PaymentPlatformResult resolveResult){
        String orderNo = resolveResult.getOutTradeNo(); //一线通订单号
        String parseResultFlag = "FAIL";
        payResponseResolveLog.setOrderNo(orderNo);
        try {
            //根据订单号对日志进行统计，判断是否是重复的回执通知
            if (payResponseResolveLogDao.countByOrderNoAndStatusAndCatchExceptionIsFalse(orderNo,
                    PayResponseResolveLog.ResolveStatusEnum.Accept.toString()) > 0) {
                //重复通知
                payResponseResolveLog.setStatus(PayResponseResolveLog.ResolveStatusEnum.Abandon.toString());
                payResponseResolveLogDao.save(payResponseResolveLog); //保存日志
                parseResultFlag = "SUCCESS";
            } else {
                //更新支付结果缓存
                updatePaymentResult(orderNo, PaymentResultEnum.WAITING);
                if (resolveResult.isSuccess()) {
                    //支付成功的处理
                    //获取公司ID，重复通知时抛出异常
                    String compId = null;
                    try {
                        compId = getComIdByOrderNo(orderNo);
                    } catch (Exception e) {
                        //重复通知
                        payResponseResolveLog.setCatchException(true);
                        payResponseResolveLog.setStatus(PayResponseResolveLog.ResolveStatusEnum.Abandon.toString());
                        payResponseResolveLog.setExceptionMsg(e.getMessage());
                        parseResultFlag = "SUCCESS";
                    }
                    //资金到账，修改业务充值记录，新增流水记录
                    arrivalAccount(compId, Double.valueOf(resolveResult.getTotalFee()) / 100.0,
                            orderNo, FundIETypeEnum.ONLINE_RECHARGE, resolveResult.getOrderId());
                    //更新支付结果缓存
                    updatePaymentResult(orderNo, PaymentResultEnum.SUCCESS);
                    logger.info("订单：" + orderNo + " 支付到账;支付方式明睿达支付平台：");
                    parseResultFlag = "SUCCESS";
                } else {
                    //支付失败的处理
                    //修改业务记录
                    jdbcTemplate.update("UPDATE T_BIZ_FUND_AJUSTMENT SET state=? WHERE bill_no=?",
                            new Object[] {FundStateEnum.FAIL.toString(), orderNo});
                    logger.info("订单：" + orderNo + " 支付失败; 支付方式：明睿达支付平台");

                    //更新支付结果缓存
                    updatePaymentResult(orderNo, PaymentResultEnum.FAIL);
                }
            }
        } catch(Exception e){
            e.printStackTrace();
            payResponseResolveLog.setCatchException(true);
            payResponseResolveLog.setExceptionMsg("处理[" + orderNo + "]的到账通知是出现异常：" + e.getMessage());
            logger.error("处理[" + orderNo + "]的到账通知是出现异常：" + e.getMessage());
        }finally {
            payResponseResolveLogDao.save(payResponseResolveLog); //保存日志
        }
        return parseResultFlag;
    }

    /**
     * 获取支付宝在线支付的页面地址
     * @param billNo 一线通支付订单号
     * @param amount 单次支付金额，单位：分
     * @param userkey 商户号
     */
    public String getOnlineAliPayUrl(String billNo, String amount, String userkey){
        try {
            String subject = "预付款" + amount + "元";
            String body = "预付款订单：" + billNo + "  金额：" + amount; //订单描述
            String sign = MD5Util.string2MD5(userkey + billNo);
            Double dbAmount = Double.valueOf(amount) * 100;
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            String encode = "UTF-8";
            String onlinePayRemoteIp = ProperUtils.getInstance().getPlayServerIp();
            onlinePayRemoteIp = "http://219.130.222.62:9003/mrdPay/";
            StringBuilder requestUrlSb = new StringBuilder(onlinePayRemoteIp);
            requestUrlSb.append("airPay/pay?body=").append(URLEncoder.encode(body, encode))
                    .append("&subject=").append(URLEncoder.encode(subject, encode))
                    .append("&totalAmount=").append(dbAmount.intValue())
                    .append("&outTradeNo=").append(billNo)
                    .append("&sign=").append(sign)
                    .append("&userKey=").append(userkey)
                    .append("&timeStart=").append(URLEncoder.encode(time, encode));
            return requestUrlSb.toString();
        }catch (Throwable t){
            t.printStackTrace();
            return null;
        }
    }
}

class PaymentPlatformResult {
    private static Logger logger = Logger.getLogger(PaymentPlatformResult.class);
    /**
     * 支付平台生成的ID
     */
    private String orderId;
    /**
     * 支付平台发出此通知的时间
     */
    private String timeEnd;
    /**
     * 微信支付订单号
     */
    private String transactionId;
    /**
     * 交易订单号
     */
    private String outTradeNo;
    /**
     * 金额（精确到分，人民币）
     */
    private String totalFee;
    /**
     * 交易状态（SUCCESS 成功，FAIL 失败）
     */
    private String status;
    /**
     * 支付组件返回的签名
     */
    private String sign;
    /**
     * 返回的消息
     */
    private String returnMsg;

    /**
     * {
     *   orderId:支付平台生成的ID，                <br/>
     *   time_end:支付平台发出此通知的时间，       <br/>
     *   transaction_id:微信支付订单号，           <br/>
     *   outTradeNo：交易订单号，                  <br/>
     *   total_fee：金额（精确到分，人民币），      <br/>
     *   status:交易状态（SUCCESS 成功，FAIL 失败）<br/>
     * }
     */
    public PaymentPlatformResult(String jsonStr) throws Exception {
        if(StringUtils.isEmpty(jsonStr)){
            return;
        }
        try {
            JSONObject jsonObject = JSON.parseObject(jsonStr);
            this.orderId = jsonObject.getString("orderId");
            this.timeEnd = jsonObject.getString("time_end");
            this.transactionId = jsonObject.getString("transaction_id");
            this.outTradeNo = jsonObject.getString("outTradeNo");
            this.totalFee = jsonObject.getString("total_fee");
            this.status = jsonObject.getString("status");
            if(jsonObject.containsKey("sign")){
                this.sign = jsonObject.getString("sign");
            }
            if(jsonObject.containsKey("returnMsg")){
                this.returnMsg = jsonObject.getString("returnMsg");
            }
        }catch (Exception e){
            logger.error("支付平台通知参数有误！！！");
            logger.error("解析时出现错误：" + e.getMessage());
            throw e;
        }
    }

    public PaymentPlatformResult(HttpServletRequest request) throws Exception {
        try {
        this.orderId = request.getParameter("orderId");
            this.timeEnd = request.getParameter("time_end");
            this.transactionId = request.getParameter("transaction_id");
            this.outTradeNo = request.getParameter("outTradeNo");
            this.totalFee = request.getParameter("total_fee");
            this.status = request.getParameter("status");
            this.sign = request.getParameter("sign");
            this.returnMsg = request.getParameter("returnMsg");
        }catch (Exception e){
            logger.error("支付平台通知参数有误！！！");
            logger.error("解析时出现错误：" + e.getMessage());
            throw e;
        }
    }

    public String getOrderId() {
        return orderId;
    }

    public String getTimeEnd() {
        return timeEnd;
    }

    public String getTransactionId() {
        return transactionId;
    }

    public String getOutTradeNo() {
        return outTradeNo;
    }

    public String getTotalFee() {
        return totalFee;
    }

    public String getStatus() {
        return status;
    }

    public String getSign() {
        return sign;
    }

    public String getReturnMsg() {
        return returnMsg;
    }

    /**
     * 判断是否支付成功
     * @return boolean类型， true 支付成功， false 支付失败
     */
    public boolean isSuccess(){
        return PaymentPlatformBiz.platformPaymentStatus.SUCCESS.toString().equals(this.status);
    }
}
